﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using VideoStore.Business.Components.Interfaces;
using VideoStore.Business.Entities;
using System.Transactions;
using VideoStore.Common;
using Microsoft.Practices.ServiceLocation;
using MessageBus.Interfaces;
using VideoStore.Business.Components.Commands;

namespace VideoStore.Business.Components
{
    public class OrderProvider : IOrderProvider
    {
        private IEmailProvider EmailProvider
        {
            get
            {
                return ServiceLocator.Current.GetInstance<IEmailProvider>();
            }
        }

        public void CreateOrder(Entities.Order pOrder)
        {
            EntityInsertCommand<Order> lOrderCreateCmd = new EntityInsertCommand<Order>(pOrder);
            lOrderCreateCmd.Execute();
        }

        public Order GetOrderById(int pId)
        {
            using (VideoStoreEntityModelContainer lContainer = new VideoStoreEntityModelContainer())
            {
                lContainer.ContextOptions.LazyLoadingEnabled = false;
                return (from order in lContainer.Orders.Include("OrderItems.Media.Stocks").Include("Customer") where order.Id == pId select order).FirstOrDefault();
            }
        }

        public void UpdateOrder(Order pOrder)
        {
            using(TransactionScope lScope = new TransactionScope())
            using (VideoStoreEntityModelContainer lContainer = new VideoStoreEntityModelContainer())
            {
                lContainer.Orders.Attach(pOrder);
                lContainer.ObjectStateManager.ChangeObjectState(pOrder, System.Data.EntityState.Modified);
                lContainer.SaveChanges();
                lScope.Complete();
            }
        }

        public void SubmitOrder(Entities.Order pOrder)
        {
            String lMessage = String.Format("Your order has been submitted successfully");
            try
            {
                /**
                ServiceLocator.Current.GetInstance<IPublisherService>().Publish(
                    CommandFactory.Instance.GetSubmitOrderCommand(pOrder)
                );
                **/
                CreateOrder(pOrder);
                TransferService.TransferServiceClient lClient = new TransferService.TransferServiceClient();
                lClient.Transfer(System.Convert.ToDecimal(pOrder.Total), pOrder.Customer.BankAccountNumber, GetStoreAcctNumber(), pOrder.Id.ToString());
            }
            catch (Exception lException)
            {
                lMessage = lException.Message;
                throw;
            }
            finally
            {
                //EmailProvider.SendMessage(pOrder.Customer.Email, lMessage);
            }
        }

        public void CancelOrder(int orderId)
        {
            try
            {
                Order pOrder = GetOrderById(orderId);
                ServiceLocator.Current.GetInstance<IEmailProvider>().SendMessage(pOrder.Customer.Email, "Reversing bank transaction for your order " + orderId + ".");
                TransferService.TransferServiceClient lClient = new TransferService.TransferServiceClient();
                lClient.Transfer(System.Convert.ToDecimal(pOrder.Total), GetStoreAcctNumber(), pOrder.Customer.BankAccountNumber, "reverse" + pOrder.Id.ToString());
            }
            catch (Exception lException)
            {
                System.Diagnostics.Debug.WriteLine(lException.Message);
                throw;
            }
        }

        public void ConfirmOrder(Boolean outcome, int orderId, Boolean reverseTransaction)
        {
            Order pOrder = GetOrderById(orderId);
            String email = pOrder.Customer.Email;
            // update stock level after bank transfer is successful
            if (outcome && !reverseTransaction)
            {
                try
                {    
                    using (TransactionScope lScope = new TransactionScope())
                    using (VideoStoreEntityModelContainer lContainer = new VideoStoreEntityModelContainer())
                    {
                        lContainer.Orders.Attach(pOrder);
                        lContainer.ObjectStateManager.ChangeObjectState(pOrder, System.Data.EntityState.Modified);
                        pOrder.UpdateStockLevels();
                        lContainer.ApplyChanges<Order>("Orders", pOrder);
                        lContainer.SaveChanges();
                        lScope.Complete();
                    }
                    ServiceLocator.Current.GetInstance<IEmailProvider>().SendMessage(email, "Your order " + orderId + " has been fulfilled.");
                }
                catch(Exception lException)
                {
                    // insufficient stock, reverse bank transfer
                    System.Diagnostics.Debug.WriteLine(lException.Message);
                    CancelOrder(orderId);
                }
            }
            // reverse bank transfer request failed, try again. loops forever if reverse bank transfers fails
            else if (!outcome && reverseTransaction)
            {
                CancelOrder(orderId);
            }
            // inform customer order was no successful due to insufficient stock
            else if (outcome && reverseTransaction)
            {
                ServiceLocator.Current.GetInstance<IEmailProvider>().SendMessage(email, "Insufficient stock. Your order " + orderId + " is not fulfilled.");
            }
            // inform customer bank transfer failed due to insufficient funds
            else if (!outcome && !reverseTransaction)
            {
                ServiceLocator.Current.GetInstance<IEmailProvider>().SendMessage(email, "Insufficient funds for bank transfer. Your order " + orderId + " is not fulfilled.");
            }
        }

        private int GetStoreAcctNumber()
        {
            return 123;
        }
    }
}
